package com.ai.chat.service.impl;

/**
 * ClassName:    ChatServiceImpl
 * Description:  TODO
 * Author:       yuzx
 * Date:         2025/9/8 14:27
 * Version:      1.0
 **/

import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.ai.chat.domain.ChatMessage;
import com.ai.chat.domain.ChatSession;
import com.ai.chat.service.IChatService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**

 聊天服务实现类（完全匹配 DashScope SDK 源码结构）
 @author ruoyi
 */
@Service
public class ChatServiceImpl implements IChatService {
    // 模型名称（需与阿里云百炼模型列表一致，参考文档：https://help.aliyun.com/zh/model-studio/getting-started/models）
    private static final String MODEL_NAME = "qwen-plus";
    // 系统提示（引导模型行为）
    private static final String SYSTEM_PROMPT = "记住你的名字叫做GGBao,你是一个 helpful 的助手，基于用户的问题提供准确、简洁的回答。";
    // 用户会话存储（生产环境建议替换为 Redis，支持分布式部署）
    private final Map<Long, ChatSession> userSessions = new ConcurrentHashMap<>();
    // 从配置文件注入 DashScope API Key（优先配置文件，其次环境变量）
    @Value ("${dashscope.api-key:}")
    private String apiKey;
    @Override
    public String sendMessage (Long userId, String content) {
        try {
            // 1. 获取 / 创建用户会话（保证多轮对话上下文连续性）
            ChatSession session = getUserSession (userId);
            // 2. 追加用户消息到会话历史
            session.getMessages ().add (new ChatMessage (Role.USER, content));
            session.setLastUpdateTime (System.currentTimeMillis ());
            // 3. 转换为 DashScope SDK 要求的 Message 格式
            List<Message> dashScopeMessages = convertToDashScopeMessages(session.getMessages());
            // 4. 用源码提供的 Builder 构建 GenerationParam
            GenerationParam param = buildGenerationParam (dashScopeMessages);
            // 5. 调用 DashScope API 获取 AI 回复
            GenerationResult result = new Generation ().call (param);
            // 6. 解析回复并追加到会话历史
            String assistantReply = parseAssistantReply (result);
            session.getMessages ().add (new ChatMessage (Role.ASSISTANT, assistantReply));
            // 7. 上下文长度管理（防止超出模型 Token 限制，避免报错）
            manageContextLength (session);
            return assistantReply;
        } catch (ApiException e) {
            throw new RuntimeException ("AI 服务调用失败（API 异常）:" + e.getMessage (), e);
        } catch (NoApiKeyException e) {
            throw new RuntimeException ("API Key 未配置（请检查配置文件或环境变量）:" + e.getMessage (), e);
        } catch (InputRequiredException e) {
            throw new RuntimeException ("必要参数缺失:" + e.getMessage (), e);
        } catch (Exception e) {
            throw new RuntimeException ("对话处理异常:" + e.getMessage (), e);
        }
    }
    @Override
    public void clearHistory (Long userId) {
        ChatSession session = userSessions.get (userId);
        if (session != null) {
            session.getMessages ().clear ();
            // 重新添加系统提示（保证会话初始状态正确）
            session.getMessages ().add (new ChatMessage (Role.SYSTEM, SYSTEM_PROMPT));
            session.setLastUpdateTime (System.currentTimeMillis ());
        }
    }
    @Override
    public List<ChatMessage> getHistory(Long userId) {
        return getUserSession(userId).getMessages();
    }
//------------------------------ 私有工具方法 ------------------------------
    /**
     获取或创建用户会话（保证每个用户独立上下文）
     */
    private ChatSession getUserSession (Long userId) {
        return userSessions.computeIfAbsent (userId, k -> {
            ChatSession session = new ChatSession ();
            session.setSessionId (UUID.randomUUID ().toString ());
            session.setUserId (userId);
            session.setCreateTime (System.currentTimeMillis ());
            session.setLastUpdateTime (System.currentTimeMillis ());
            // 初始会话必须包含系统提示（引导模型行为）
            session.getMessages ().add (new ChatMessage (Role.SYSTEM, SYSTEM_PROMPT));
            return session;
        });
    }
    /**
     构建 GenerationParam（完全遵循源码的 Builder 模式，核心修复）
     参考源码：public static GenerationParamBuilder builder()
     */
    private GenerationParam buildGenerationParam(List<Message> messages) {
// 1. 获取源码提供的构建器
        GenerationParam.GenerationParamBuilder builder = GenerationParam.builder();
// 2. 设置模型（必须与阿里云百炼支持的模型名一致）
        builder.model (MODEL_NAME);
// 3. 设置对话上下文（多轮对话的核心）
        builder.messages (messages);
// 4. 设置结果格式（与前端交互建议用 MESSAGE 格式，包含角色信息）
        builder.resultFormat (GenerationParam.ResultFormat.MESSAGE);
// 5. 设置 API Key（优先用配置文件，其次用环境变量）
        String finalApiKey = (apiKey != null && !apiKey.trim ().isEmpty ())
                ? apiKey.trim ()
                : System.getenv ("DASHSCOPE_API_KEY");
        builder.apiKey (finalApiKey); // 父类 GenerationParamBase 的 Builder 方法，源码隐含支持
// 6. 可选：设置生成参数（控制回复质量，根据需求调整）
        builder.temperature (0.7f) // 0-1，值越高回复越灵活，越低越严谨
                .maxTokens (8192); // 最大回复长度（需参考模型的 Token 限制，qwen-plus 默认支持 8192）
// 7. 构建最终参数对象（源码要求通过 build () 方法生成）
        return builder.build ();
    }
    /**
     转换为 DashScope SDK 要求的 Message 格式（使用 Message 的 Builder 模式，匹配源码用法）
     */
    private List<Message> convertToDashScopeMessages(List<ChatMessage> ourMessages) {
        List<Message> dashMessages = new ArrayList<>(ourMessages.size());
        for (ChatMessage ourMsg : ourMessages) {
            // 修复：直接使用String类型的role，无需调用getValue()
            Message dashMsg = Message.builder()
                    .role(ourMsg.getRole())
                    .content(ourMsg.getContent())
                    .build();
            dashMessages.add(dashMsg);
        }
        return dashMessages;
    }
    /**
     解析 AI 回复（兼容 MESSAGE 格式的返回结果）
     */
    private String parseAssistantReply (GenerationResult result) {
        if (result == null || result.getOutput () == null
                || result.getOutput ().getChoices () == null
                || result.getOutput ().getChoices ().isEmpty ()) {
            throw new RuntimeException ("AI 回复格式异常，无有效内容");
        }
// 从返回结果中提取助手回复（MESSAGE 格式下包含 role 和 content）
        Message assistantMsg = result.getOutput ().getChoices ().get (0).getMessage ();
        if (assistantMsg == null || assistantMsg.getContent () == null) {
            throw new RuntimeException ("AI 回复内容为空");
        }
        return assistantMsg.getContent ().trim ();
    }
    /**
     上下文长度管理（防止超出模型最大 Token 限制，避免调用报错）
     策略：保留系统提示 + 最近 20 轮对话（可根据模型 Token 限制调整）
     */
    private void manageContextLength (ChatSession session) {
        List<ChatMessage> messages = session.getMessages ();
        int maxKeepCount = 21; // 1 条系统提示 + 20 轮对话（用户 + 助手各算 1 轮）
        if (messages.size() > maxKeepCount) {
            List<ChatMessage> newMessages = new ArrayList<>();
// 保留第一条系统提示
            newMessages.add (messages.get (0));
// 保留最近的 20 条消息（截断早期对话）
            newMessages.addAll (messages.subList (messages.size () - 20, messages.size ()));
            session.setMessages (newMessages);
        }
    }
}